/*
 * File:   ModuleLoader.h
 * Author: pkv
 *
 * Created on July 30, 2011, 5:40 PM
 *
 * Implements a dynamic module loading subsystem that can load modules from
 * shared libraries.
 *
 * The loader itself uses a singleton to maintain a cache of currently loaded
 * modules, allowing calling code to query and browse the modules by name.
 */

#ifndef MODULELOADER_H
#define	MODULELOADER_H

#include "Module.h"
#include "Lock.h"
#include "Mutex.h"

#include <SLB3/slb.h>
#include <vector>
#include <string>
#include <map>

class ModuleLoader
{
public:
    void *load(const std::string moduleName, void *param = NULL, const std::string path = "");
    template<class T> void *load(void *param = NULL);

    void *unload(const std::string moduleName, void *param = NULL);
    template<class T> void *unload(void *param = NULL);

    std::vector<std::string> list();

private:

    typedef struct
    {
        union
        {
            void *lib;
            Module::Definition *def;
        } ptr;
        std::string tmpFile;
        bool isShared;
    } ModuleRef;

    static Mutex _moduleLock;
    static std::map<std::string, ModuleRef> _modules;

    std::string registerModuleName(std::string name);
    std::string unregisterModuleName(std::string name);
};

SLB3_DECLARATION(ModuleLoader, "plinth.ModuleLoader", policy::Default);

template <class T>
void *ModuleLoader::load(void *param)
{
    Lock lock(_moduleLock);
    Module::Definition *def = new T();

    // Call the module's registration function
    void *result = def->registerFn(param);

    // Add the module to the loaded list
    _modules[def->name()].isShared = false;
    _modules[def->name()].ptr.def = def;

    return result;
}

template <class T>
void *ModuleLoader::unload(void *param)
{
    Module::Definition *def = new T();
    return unload(def->name(), param);
}

#endif	/* MODULELOADER_H */

